package com.star.eastern.blee.utils

import android.annotation.SuppressLint
import android.os.AsyncTask
import android.util.Log
import com.tangula.android.utils.ToastUtils
import org.apache.commons.lang3.StringUtils
import java.lang.Exception
import java.util.*
import java.util.concurrent.PriorityBlockingQueue


class CommandCenter {

    companion object {


        @JvmStatic
        private var COMMAND_QUEUE: Queue<CommandInstance> = PriorityBlockingQueue<CommandInstance>()

        @JvmStatic
        private val LOCK = Object()

        @JvmStatic
        var CURRENT_COMMAND: CommandInstance? = null //当前命令

        @JvmStatic
        private var CURRENT_RESP: String? = null //当前命令之后后的应答信息

        private var ON_STAT_UPDATE: ((String) -> Unit)? = null

        var DEFAULT_STAT_CHECK_INTERVAL_TIME = 200L

        var DEFAULT_WAIT_TIME = 60000L

        private var LOOP_TASK: AsyncTask<Unit, Unit, Unit>? = null

        fun regOnStatUpdateListener(listener: ((String) -> Unit)?) {
            ON_STAT_UPDATE = listener
        }

        fun isNoResponseCommand():Boolean{
            return CURRENT_COMMAND?.command?.answerType()==CommandAnswerType.NONE
        }

        fun isRunning():Boolean{
            return CURRENT_COMMAND!=null
        }

        fun fetchCurrentCommandInstance():CommandInstance?{
            return CURRENT_COMMAND
        }

        fun notifyDeviceError(){
            try {
                LOCK.notifyAll()
            }catch (e:Exception){
                //SKIP
            }
        }

        @JvmStatic
        fun startLoop() {
            if (LOOP_TASK == null) {
                LOOP_TASK = @SuppressLint("StaticFieldLeak")
                object : AsyncTask<Unit, Unit, Unit>() {
                    override fun doInBackground(vararg params: Unit?) {
                        //Log.i("console", "BLE COMMAND CENTER STARTED")
                        while (true) {
                            if (Tripple7BluetoothCommandProtocol.isConnected())
                                if (COMMAND_QUEUE.isEmpty()) {
                                    if (CURRENT_COMMAND == null) {
                                       acceptCommand(CommandEnum.STAT, CommandEnum.STAT.name, ON_STAT_UPDATE)
                                    }
                                    Thread.sleep(DEFAULT_STAT_CHECK_INTERVAL_TIME)
                                } else {
                                    synchronized(LOCK) {
                                        CURRENT_COMMAND = COMMAND_QUEUE.poll()
                                        CURRENT_COMMAND?.also { cur ->
                                            try {
                                                //Log.v("console", "IN LOOP---------${CURRENT_COMMAND?.command}----${COMMAND_QUEUE?.size?:-100}")
                                                Tripple7BluetoothCommandProtocol.currentGatt?.also { gatt->
                                                    //gatt.disconnect()
                                                    gatt.connect()
                                                }
                                                Tripple7BluetoothCommandProtocol.sendCmd(if(StringUtils.isBlank(cur.text)) cur.command.name else cur.text!!) { resp ->
                                                    CURRENT_RESP = resp
                                                    try {
                                                        LOCK.notifyAll()
                                                    }catch (e:Exception){
                                                        //SKIP
                                                    }
                                                }
                                                //LogConsole.writeBizLog("wait time: $DEFAULT_WAIT_TIME")
                                                LOCK.wait(DEFAULT_WAIT_TIME)

                                            } catch (e: Exception) {
                                                //Log.v("console", e.localizedMessage, e)
                                                cur.onError?.also { func -> func(e) }
                                            }
                                            if (CURRENT_RESP == null&&cur.command.answerType()!=CommandAnswerType.NONE) {
                                                cur.onError?.also { func -> func(null) }
                                            } else {
                                                cur.onResponse?.also { func -> func.invoke(CURRENT_RESP ?: "") }
                                            }
                                            CURRENT_COMMAND = null
                                            CURRENT_RESP = null

                                            //Tripple7BluetoothCommandProtocol.currentGatt?.also { gatt->
                                                //gatt.disconnect()
                                            //}
                                        }
                                    }
                                }
                        }
                    }
                }

                LOOP_TASK?.also { task -> task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) }
            }
        }

        fun acceptCommand(cmd: CommandEnum, text: String, onResp: ((String) -> Unit)?) {
            acceptCommand(cmd, text, onResp) { ex-> LogConsole.writeBizLog("A Command execute fail", ex) }
        }

        fun acceptCommand(cmd: CommandEnum, text: String, onResp: ((String) -> Unit)?, onFail: ((Exception?) -> Unit)?) {
            if (!isContainCommand(cmd)) {
                COMMAND_QUEUE.offer(
                    CommandInstance(
                        cmd,
                        text,
                        onResp,
                        onFail
                    )
                )
            }
        }

        fun isContainCommand(cmd: CommandEnum): Boolean {
            synchronized(COMMAND_QUEUE) {
                for (cur in COMMAND_QUEUE) {
                    if (cur.command == cmd) {
                        return true
                    }
                }
            }
            return false
        }


    }

}